﻿namespace GreenIsomer.Web.Controls.JQuery {
	using System;
	using System.Collections;
	using System.Collections.Generic;
	using System.ComponentModel;
	using System.Globalization;
	using System.Text;

	/// <summary>
	/// Provides a specialized collection of localized month names.
	/// </summary>
	[TypeConverter(typeof(MonthNameCollectionConverter))]
	public class MonthNameCollection : IEnumerable<string> {


		#region Constants

		private const int monthCount = 12;

		#endregion


		#region Members

		private Culture culture;
		private string[] customNames;

		#endregion


		#region Constructors

		/// <summary>
		/// Initializes a new instance of the GreenIsomer.Web.Controls.JQuery.MonthNameCollection class.
		/// </summary>
		/// <param name="length">The GreenIsomer.Web.Controls.JQuery.MonthNameLength value representing the standard client-side jQuery UI month name length.</param>
		public MonthNameCollection(MonthNameLength length) {
			customNames = new string[monthCount];
			Length = length;
		}

		#endregion


		#region Indexers

		/// <summary>
		/// Returns the localized month using a zero-based index.
		/// </summary>
		/// <param name="month">Zero-based index for the month (0 represents January).</param>
		/// <returns>The localized month.</returns>
		public string this[int month] {
			get { return GetName(month); }
			set { SetName(month, value); }
		}

		#endregion


		#region Properties: Public

		/// <summary>
		/// Gets the number of items in the collection.
		/// </summary>
		[Browsable(false)]
		public MonthNameLength Length { get; private set; }

		/// <summary>
		/// Gets or sets the culture associated with the collection.
		/// </summary>
		[DefaultValue(Culture.Invariant), RefreshProperties(RefreshProperties.Repaint), ParenthesizePropertyName(true)]
		public Culture Culture {
			get { return culture; }
			set { culture = value; }
		}

		/// <summary>
		/// Gets or sets the localized name for January.
		/// </summary>
		[RefreshProperties(RefreshProperties.Repaint)]
		public string January {
			get { return GetName(0); }
			set { SetName(0, value); }
		}

		/// <summary>
		/// Gets or sets the localized name for February.
		/// </summary>
		[RefreshProperties(RefreshProperties.Repaint)]
		public string February {
			get { return GetName(1); }
			set { SetName(1, value); }
		}

		/// <summary>
		/// Gets or sets the localized name for March.
		/// </summary>
		[RefreshProperties(RefreshProperties.Repaint)]
		public string March {
			get { return GetName(2); }
			set { SetName(2, value); }
		}

		/// <summary>
		/// Gets or sets the localized name for April.
		/// </summary>
		[RefreshProperties(RefreshProperties.Repaint)]
		public string April {
			get { return GetName(3); }
			set { SetName(3, value); }
		}

		/// <summary>
		/// Gets or sets the localized name for May.
		/// </summary>
		[RefreshProperties(RefreshProperties.Repaint)]
		public string May {
			get { return GetName(4); }
			set { SetName(4, value); }
		}

		/// <summary>
		/// Gets or sets the localized name for June.
		/// </summary>
		[RefreshProperties(RefreshProperties.Repaint)]
		public string June {
			get { return GetName(5); }
			set { SetName(5, value); }
		}

		/// <summary>
		/// Gets or sets the localized name for July.
		/// </summary>
		[RefreshProperties(RefreshProperties.Repaint)]
		public string July {
			get { return GetName(6); }
			set { SetName(6, value); }
		}

		/// <summary>
		/// Gets or sets the localized name for August.
		/// </summary>
		[RefreshProperties(RefreshProperties.Repaint)]
		public string August {
			get { return GetName(7); }
			set { SetName(7, value); }
		}

		/// <summary>
		/// Gets or sets the localized name for September.
		/// </summary>
		[RefreshProperties(RefreshProperties.Repaint)]
		public string September {
			get { return GetName(8); }
			set { SetName(8, value); }
		}

		/// <summary>
		/// Gets or sets the localized name for October.
		/// </summary>
		[RefreshProperties(RefreshProperties.Repaint)]
		public string October {
			get { return GetName(9); }
			set { SetName(9, value); }
		}

		/// <summary>
		/// Gets or sets the localized name for November.
		/// </summary>
		[RefreshProperties(RefreshProperties.Repaint)]
		public string November {
			get { return GetName(10); }
			set { SetName(10, value); }
		}

		/// <summary>
		/// Gets or sets the localized name for December.
		/// </summary>
		[RefreshProperties(RefreshProperties.Repaint)]
		public string December {
			get { return GetName(11); }
			set { SetName(11, value); }
		}

		#endregion


		#region Properties: Protected

		/// <summary>
		/// Gets a System.Globalization.DateTimeFormatInfo object defining how System.DateTime values are rendered for the specified Culture value.
		/// </summary>
		[Browsable(false)]
		protected virtual DateTimeFormatInfo Format {
			get {
				switch(Culture) {
					case Culture.Invariant: return DateTimeFormatInfo.InvariantInfo;
					case Culture.Current: return DateTimeFormatInfo.CurrentInfo;
					default: return null;
				}
			}
		}

		#endregion


		#region Methods: Public

		/// <summary>
		/// Returns an enumerator that iterates through a collection. 
		/// </summary>
		/// <returns>An IEnumerator object that can be used to iterate through the collection.</returns>
		public IEnumerator<string> GetEnumerator() {
			yield return January;
			yield return February;
			yield return March;
			yield return April;
			yield return May;
			yield return June;
			yield return July;
			yield return August;
			yield return September;
			yield return October;
			yield return November;
			yield return December;
		}

		/// <summary>
		/// Returns a System.String that represents the current GreenIsomer.Web.Controls.JQuery.DayNameCollection value.
		/// </summary>
		/// <returns>The string representation.</returns>
		public override string ToString() {
			if(Culture == Culture.Custom)
				return string.Format(CultureInfo.InvariantCulture, "(Custom: {0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10}, {11})",
					January, February, March, April, March, June, July, August, September, October, November, December);

			return string.Format(CultureInfo.InvariantCulture, "({0})", culture.ToString());
		}

		/// <summary>
		/// Converts the collection to a string array.
		/// </summary>
		/// <returns>A string array of values.</returns>
		public string[] ToArray() {
			string[] result = new string[monthCount];
			for(int index = 0; index < result.Length; index++)
				result[index] = GetName(index);
			return result;
		}

		#endregion


		#region Methods: Protected

		/// <summary>
		/// Gets the localized name for the provided month.
		/// </summary>
		/// <param name="month">A zero-based index representing the day of the week (0 represents January).</param>
		/// <returns>The localized month name.</returns>
		protected virtual string GetName(int month) {
			if(month < 0 || month >= monthCount) throw new ArgumentOutOfRangeException("month");

			DateTimeFormatInfo format = Format;
			if(format == null)
				return customNames[month] ?? GetNameFromFormat(DateTimeFormatInfo.InvariantInfo, month);
			return GetNameFromFormat(format, month);
		}

		/// <summary>
		/// Sets the localized name for the provided month.
		/// </summary>
		/// <param name="month">A zero-based index representing the day of the week (0 represents January).</param>
		/// <param name="value">The localized month name.</param>
		protected virtual void SetName(int month, string value) {
			if(month < 0 || month >= monthCount) throw new ArgumentOutOfRangeException("month");

			string oldName = GetName(month);
			if(oldName != value) {
				if(string.IsNullOrEmpty(value) || (value == GetNameFromFormat(DateTimeFormatInfo.InvariantInfo, month)))
					customNames[month] = null;
				else
					customNames[month] = value;
			}
			Culture = Culture.Custom;
		}

		/// <summary>
		/// Looks up the standard month name from the provided System.Globalization.DateTimeFormatInfo object.
		/// </summary>
		/// <param name="format">A System.Globalization.DateTimeFormatInfo object containing format information for System.DateTime objects.</param>
		/// <param name="month">A zero-based index representing the day of the week (0 represents January).</param>
		/// <returns>The localized month name.</returns>
		protected virtual string GetNameFromFormat(DateTimeFormatInfo format, int month) {
			if(month < 0 || month >= monthCount) throw new ArgumentOutOfRangeException("month");

			switch(Length) {
				case MonthNameLength.Short: return format.GetAbbreviatedMonthName(month + 1);
				default: return format.GetMonthName(month + 1);
			}
		}

		#endregion


		#region Methods: Serialization

		private void Reset(int month) {
			customNames[month] = null;
		}

		private bool ShouldSerialize(int month) {
			if(Culture != Culture.Custom)
				return false;
			return (customNames[month] != null);
		}

		private bool ShouldSerializeJanuary() {
			return ShouldSerialize(0);
		}
		private bool ShouldSerializeFebruary() {
			return ShouldSerialize(1);
		}
		private bool ShouldSerializeMarch() {
			return ShouldSerialize(2);
		}
		private bool ShouldSerializeApril() {
			return ShouldSerialize(3);
		}
		private bool ShouldSerializeMay() {
			return ShouldSerialize(4);
		}
		private bool ShouldSerializeJune() {
			return ShouldSerialize(5);
		}
		private bool ShouldSerializeJuly() {
			return ShouldSerialize(6);
		}
		private bool ShouldSerializeAugust() {
			return ShouldSerialize(7);
		}
		private bool ShouldSerializeSeptember() {
			return ShouldSerialize(8);
		}
		private bool ShouldSerializeOctober() {
			return ShouldSerialize(9);
		}
		private bool ShouldSerializeNovember() {
			return ShouldSerialize(10);
		}
		private bool ShouldSerializeDecember() {
			return ShouldSerialize(11);
		}

		private void ResetJanuary() {
			Reset(0);
		}
		private void ResetFebruary() {
			Reset(1);
		}
		private void ResetMarch() {
			Reset(2);
		}
		private void ResetApril() {
			Reset(3);
		}
		private void ResetMay() {
			Reset(4);
		}
		private void ResetJune() {
			Reset(5);
		}
		private void ResetJuly() {
			Reset(6);
		}
		private void ResetAugust() {
			Reset(7);
		}
		private void ResetSeptember() {
			Reset(8);
		}
		private void ResetOctober() {
			Reset(9);
		}
		private void ResetNovember() {
			Reset(10);
		}
		private void ResetDecember() {
			Reset(11);
		}

		#endregion


		#region Explicit implementation: IEnumerable

		IEnumerator IEnumerable.GetEnumerator() {
			return GetEnumerator();
		}

		#endregion


	}

}